package com.itcast.zk.election;

import org.apache.zookeeper.*;

import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * <p>Description: </p>
 *
 * @author
 * @version 1.0
 * <p>Copyright:Copyright(c)2020</p>
 * @date
 */
public class FairElection {
    
    /**
     * ZK连接地址
     */
    private static String connectAddr = "192.168.23.129:2181";
    
    /**
     * ZK客户端
     */
    private static ZooKeeper zk = null;
    
    /**
     * 记录所创建的节点编号
     */
    private static String zkNode = null;
    
    /**
     * 连接超时时间（单位： 毫秒）
     */
    private static int sessionTimeout = 10000;
    
    public static void main(String[] args) throws Exception {
        
        // 服务编号
        String serverNo = "Leader" + 5;
        // 启动连接
        zk = new ZooKeeper(connectAddr, sessionTimeout, new Watcher() {
            @Override
            public void process(WatchedEvent event) {
                System.out.println(serverNo + " startup: " + event.getState());
            }
        });
        
        //1、创建选举节点, 这里是采用临时有序节点
        zkNode = zk.create("/master/election", serverNo.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
        
        // 模拟服务器进行选举监听
        selection(serverNo);
        
        // 阻塞主线程
        TimeUnit.HOURS.sleep(1);
    }
    
    /**
     * 公平选举处理流程
     *
     * @throws Exception
     */
    private static void selection(String serverNo) throws Exception {
        
        try {
            //2、遍历/master下的子节点，判断编号是否最小
            List<String> children = zk.getChildren("/master", null);
            Collections.sort(children);
            
            String formerNode = "";  //前一个节点，用于监听
            for (int i = 0; i < children.size(); i++) {
                String node = children.get(i);
                if (zkNode.equals("/master/" + node)) {
                    if (i == 0) {
                        //第一个
                        System.out.println(serverNo + "被选为leader节点了");
                    } else {
                        formerNode = children.get(i - 1);
                    }
                }
            }
            if (!"".equals(formerNode)) {
                //自己不是第一个，如果是第一个formerNode应该没有值
                System.out.println(serverNo + "竞选失败了");
                //3、监听前一个节点的删除事件，如果删除了，重新进行选举
                zk.getData("/master/" + formerNode, new Watcher() {
                    @Override
                    public void process(WatchedEvent event) {
                        System.out.println(event.getType() + "---" + event.getPath() + "---" + event.getState());
                        try {
                            if (Objects.equals(event.getType(), Event.EventType.NodeDeleted)) {
                                selection(serverNo);
                            }
                        } catch (Exception e) {
                        }
                    }
                }, null);
            }
            
        } catch (Exception e) {
            System.out.println(serverNo + ": 选举失败, " + e.getMessage());
        }
    }
    
}
